using System;
using System.Collections;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Policy;
using PHSRAG.Utility;
using Constants = PHSRAG.Insight21.InsightUtilities.Constants;
using Enums = PHSRAG.Security.Enumerations;

namespace PHSRAG.Insight21.Admin
{
    /// <summary>
    /// Allows users to search for Labs within insight.
    /// </summary>
    public partial class AdminSearchLabs : BasePage
    {
        #region Constants

        private const string FirstNameKey = "FirstName_8DD4FB62-755A-418f-B73A-07E79FA2A5B5";
        private const string LabNameKey = "LabName_8DD4FB62-755A-418f-B73A-07E79FA2A5B5";
        private const string LabsKey = "Labs_8DD4FB62-755A-418f-B73A-07E79FA2A5B5";
        private const string LastNameKey = "LastName_8DD4FB62-755A-418f-B73A-07E79FA2A5B5";
        private const string OrganizationIDKey = "OrganizationID_8DD4FB62-755A-418f-B73A-07E79FA2A5B5";
        private const string SortColumnKey = "SortColumn_8DD4FB62-755A-418f-B73A-07E79FA2A5B5";
        private const string SortDirectionKey = "SortAscending_8DD4FB62-755A-418f-B73A-07E79FA2A5B5";
        private const string UsernameKey = "Username_8DD4FB62-755A-418f-B73A-07E79FA2A5B5";

        #endregion

        #region Instance Variables (Private)

        private ICachePolicy objectCachePolicy;
        private ICachePolicy pageCachePolicy;

        #endregion

        #region Private Properties

        /// <summary>
        /// Private boolean property used to get/set if the sort order is ascending or descending.
        /// This value is stored as a name / value pair in a hash table stored in the intra page cache under the 
        /// page's key.
        /// </summary>
        private bool SortAscending
        {
            get
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.SearchLabsPageKey) as Hashtable;

                if (h == null)
                {
                    return false;
                }

                object sortAscending = h[SortDirectionKey];
                return (sortAscending == null) ? false : (bool) sortAscending;
            }
            set
            {
                Hashtable h = pageCachePolicy.GetCachedObject(Keys.SearchLabsPageKey) as Hashtable ?? new Hashtable();
                h[SortDirectionKey] = value;
                pageCachePolicy.Cache(Keys.SearchLabsPageKey, h);
            }
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Adds the breadcrumb for the page, sets up the add lab button to launch
        /// the Add lab pop up.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Information accompanying the event itself.</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            annunciator.Message = string.Empty;
            breadCrumb.Add("Search Labs", "AdminSearchLabs.aspx", Settings.GetKeyValue("BreadCrumb.SummaryPageLevel", 1));

            if (!IsPostBack && postbackGuard.IsValid)
            {
                const string popUpFeatures = "width=600,height=400,scrollbars=yes,resizable=yes,status=no";
                const string popUpHostPage = "../Common/ControlHost.aspx";
                const string addLabWizardControl = "../Admin/AdminControls/AddAdminLab.ascx";

                addLab.Attributes["onclick"] = string.Format("window.open('{0}?Load={1}', 'AddLabWizard', '{2}');return false;",
                    popUpHostPage, addLabWizardControl, popUpFeatures);

                // check if the search criteria is in cache, checking for only one criteria should suffice as
                // if one is in cached, the rest should be as well
                object cachedLabName = pageCachePolicy.GetCachedObject(LabNameKey);
                if (cachedLabName != null)
                {
                    labName.Text = (string) cachedLabName;
                    piUsername.Text = (string) pageCachePolicy.GetCachedObject(UsernameKey);
                    piFirstName.Text = (string) pageCachePolicy.GetCachedObject(FirstNameKey);
                    piLastName.Text = (string) pageCachePolicy.GetCachedObject(LastNameKey);
                    organizationSelectors.SelectedOrganizationID = (int) pageCachePolicy.GetCachedObject(OrganizationIDKey);
                    LoadDataGrid(GetLabs().GetDataContainer());
                }
                ManageControlVisibility();
                annunciator.Message = string.Empty;
            }
        }

        /// <summary>
        /// Adds the sort symbol to all sortable columns.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Information accompanying the event itself.</param>
        protected void OnItemCreated(object sender, DataGridItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.Header)
            {
                Label sortSymbol = new Label();
                sortSymbol.Text = SortAscending ? Constants.SortAscendingText : Constants.SortDescendingText;
                sortSymbol.Font.Name = Constants.SortSymbolFontName;
                e.Item.Cells[1].Controls.Add(sortSymbol);
            }
        }

        /// <summary>
        /// Handles datagrid click event. It caches the LabID associated 
        /// with the datagrid row clicked and redirects to the Lab investigators
        /// page.
        /// </summary>
        /// <param name="source">The object raising an event.</param>
        /// <param name="e">Information accompanying the event itself.</param>
        protected void OnItemCommand(object source, DataGridCommandEventArgs e)
        {
            if (e.CommandName == "SelectLab")
            {
                Hashtable incomingData = new Hashtable();
                incomingData[Keys.LabIdKey] = e.Item.Cells[0].Text;
                pageCachePolicy.Cache(Keys.IncomingDataKey, incomingData);

                // clear the lab cache
                new Lab(objectCachePolicy).UnCache();

                Response.Redirect("AdminLabInvestigators.aspx");
            }
        }

        /// <summary>
        /// Deletes all selected labs and refreshes the page.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Information accompanying the event itself.</param>
        protected void OnDeleteLabs(object sender, ImageClickEventArgs e)
        {
            try
            {
                Labs labs = GetLabs();
                DataTable labsDataTable = labs.LabsDataTable;
                foreach (DataGridItem item in dataGrid.Items)
                {
                    if (((CheckBox) item.FindControl("deleteLab")).Checked)
                    {
                        labsDataTable.Select(string.Format("Id = {0}", item.Cells[0].Text))[0].Delete();
                    }
                }
                labs.Save(DataAccess.GetConnectionString());

                Hashtable h = (Hashtable) pageCachePolicy.GetCachedObject(Keys.SearchLabsPageKey);
                h[LabsKey] = labs;
                pageCachePolicy.Cache(Keys.SearchLabsPageKey, h);

                // refresh the page to display new lab list after deletion
                Response.Redirect("AdminSearchLabs.aspx", false);
            }
            catch (Exception ex)
            {
                annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
            }
        }

        /// <summary>
        /// Instigates lab search and caches search criteria.
        /// </summary>
        /// <param name="sender">The object raising an event.</param>
        /// <param name="e">Information accompanying the event itself.</param>
        protected void OnSearch(object sender, ImageClickEventArgs e)
        {
            if (Page.IsValid)
            {
                pageCachePolicy.UnCache(Keys.SearchLabsPageKey);

                LoadDataGrid(GetLabs().GetDataContainer());
                ManageControlVisibility();

                pageCachePolicy.Cache(LabNameKey, labName.Text.Trim());
                pageCachePolicy.Cache(UsernameKey, piUsername.Text.Trim());
                pageCachePolicy.Cache(LastNameKey, piLastName.Text.Trim());
                pageCachePolicy.Cache(FirstNameKey, piFirstName.Text.Trim());
                pageCachePolicy.Cache(OrganizationIDKey, organizationSelectors.SelectedOrganizationID);
            }
        }

        /// <summary>
        /// Handles the datagrid sort event.
        /// </summary>
        /// <param name="source">The object raising an event.</param>
        /// <param name="e">Information accompanying the event itself.</param>
        protected void OnSort(object source, DataGridSortCommandEventArgs e)
        {
            if (e.SortExpression == "Name")
            {
                DataView labs = GetLabs().LabsDataTable.DefaultView;
                labs.Sort = string.Format("Name {0}", SortAscending ? Constants.SortViewAscending : Constants.SortViewDescending);
                SortAscending = !SortAscending;
                dataGrid.DataSource = labs;
                dataGrid.DataBind();
            }
        }

        /// <summary>
        /// Ensures at least one seach criteria is provided.
        /// </summary>
        /// <param name="source">The object raising an event.</param>
        /// <param name="args">Information accompanying the event itself.</param>
        protected void OnServerValidate(object source, ServerValidateEventArgs args)
        {
            args.IsValid = labName.Text.Trim() != string.Empty || piUsername.Text.Trim() != string.Empty
                || piLastName.Text.Trim() != string.Empty || piFirstName.Text.Trim() != string.Empty;
        }

        /// <summary>
        /// Resets the subnavigation selected link(s) before the 
        /// header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        protected void OnHeaderNavigate(object sender, CommandEventArgs e)
        {
            adminSubNavigation.Reset();
        }

        #endregion

        #region Web Form Designer generated code

        /// <summary>
        /// Initializes the page and performs event wireup.
        /// </summary>
        /// <param name="e">Information accompanying the event itself.</param>
        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);

            objectCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Loads the datagrid with lab data.
        /// </summary>
        /// <param name="labs">The dataset used to bind to the data grid.</param>
        private void LoadDataGrid(DataSet labs)
        {
            dataGrid.DataSource = labs;
            dataGrid.DataBind();
        }

        /// <summary>
        /// Hides/Shows the delete button and the grid based on if the datagrid has items in it or not.
        /// </summary>
        private void ManageControlVisibility()
        {
            deleteLabs.Visible = dataGrid.Visible = (dataGrid.Items.Count != 0);
            annunciator.Message = dataGrid.Visible ? string.Empty : "No labs returned based on search criteria supplied.";
        }

        /// <summary>
        /// If the page does not already have a cached Labs object, this method will
        /// load a new Labs object based on the user input search criteria and the 
        /// page's current sort direction.
        /// </summary>
        /// <returns>Labs object.</returns>
        private Labs GetLabs()
        {
            Hashtable h = pageCachePolicy.GetCachedObject(Keys.SearchLabsPageKey) as Hashtable ?? new Hashtable();

            object o = h[LabsKey];
            if (o == null)
            {
                string trimmedLabName = labName.Text.Trim();
                string trimmedPIUsername = piUsername.Text.Trim();
                string trimmedPILastName = piLastName.Text.Trim();
                string trimmedPIFirstName = piFirstName.Text.Trim();
                Labs labs = new Labs(objectCachePolicy);
                labs.Load(DataAccess.GetConnectionString(),
                    trimmedLabName == string.Empty ? DBNull.Value : (object) trimmedLabName,
                    trimmedPIUsername == string.Empty ? DBNull.Value : (object) trimmedPIUsername,
                    trimmedPILastName == string.Empty ? DBNull.Value : (object) trimmedPILastName,
                    trimmedPIFirstName == string.Empty ? DBNull.Value : (object) trimmedPIFirstName,
                    organizationSelectors.SelectedOrganizationID);

                h[LabsKey] = labs;

                pageCachePolicy.Cache(Keys.SearchLabsPageKey, h);
            }
            return (Labs) h[LabsKey];
        }

        #endregion
    }
}